#include "oled.h"
#include "delay.h"
/*
函数功能：SPI2接口初始化
*/
void Spi2_Pin_Init(void)
{
	//IO功能配置
	RCC->APB2ENR |=0x01<<3;
	GPIOB->CRH &=~(0xF<<20);
	GPIOB->CRH |=(0xB<<20);
	GPIOB->CRH &=~(0xF<<28);
	GPIOB->CRH |=(0xB<<28);
	
	//SPI2控制器
	RCC->APB1ENR |=0x01<<14;//时钟使能
	
	SPI2->CR1 =0;//寄存器清零
	SPI2->CR1 |=0x03<<8;//软件从设备管理
	SPI2->CR1 |=0x01<<2;//主模式

	/*
	8位数据帧格式
	高位在前
	*/
	SPI2->CR1 |=0x01<<6;//开启SPI2
}

/*
函数功能：主机发送一个字节给从机
注意事项：MODE0/3
*/
u8 Spi2_Transfer_Byte(u8 data)
{
	while(!(SPI2->SR&(0x01<<1)));
	SPI2->DR=data;
	while(!(SPI2->SR&(0x01<<0)));
	return 	SPI2->DR;
}


//OLED管脚初始化
void OLEDPinInit(void)
{
	//PB 6 7 12 
	
	RCC->APB2ENR |=1<<3;
	
	GPIOB->CRL &=~(0xFF<<24);
	GPIOB->CRL |= (0x33<<24);
	
	GPIOB->CRH &=~(0x0F<<16);
	GPIOB->CRH |= (0x03<<16);
	
	CS_H;//不片选
	RES_H;//不复位
	
}

//发送命令（1字节）
void OLED_SendCmd(uint8_t commond)
{
	CS_L;
	DC_L;
	Spi2_Transfer_Byte(commond);
	CS_H;
}


//发送显示数据（1字节）
void OLED_SendData(uint8_t data)
{
	CS_L;
	DC_H;
	Spi2_Transfer_Byte(data);
	CS_H;
}

//显示屏初始化
void OLEDInit(void)
{
	Spi2_Pin_Init( );
	OLEDPinInit( );
	
	RES_H;
	Delayms(200);
	RES_L;
	Delayms(200);
	RES_H;
	Delayms(200);
	
  OLED_SendCmd(0xAE); //关闭显示
  OLED_SendCmd(0xD5); //设置时钟分频因子,震荡频率
  OLED_SendCmd(80);   //[3:0],分频因子;[7:4],震荡频率
  OLED_SendCmd(0xA8); //设置驱动路数
  OLED_SendCmd(0X3F); //默认0X3F(1/64)
  OLED_SendCmd(0xD3); //设置显示偏移
  OLED_SendCmd(0X00); //默认为0

  OLED_SendCmd(0x40); //设置显示开始行 [5:0],行数.

  OLED_SendCmd(0x8D); //电荷泵设置
  OLED_SendCmd(0x14); //bit2，开启/关闭
  OLED_SendCmd(0x20); //设置内存地址模式
  OLED_SendCmd(0x02); //[1:0],00，列地址模式;01，行地址模式;10,页地址模式;默认10;
  OLED_SendCmd(0xA1); //段重定义设置,bit0:0,0->0;1,0->127;
  OLED_SendCmd(0xC8); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
  OLED_SendCmd(0xDA); //设置COM硬件引脚配置
  OLED_SendCmd(0x12); //[5:4]配置

  OLED_SendCmd(0x81); //对比度设置
  OLED_SendCmd(0xEF); //1~255;默认0X7F (亮度设置,越大越亮)
  OLED_SendCmd(0xD9); //设置预充电周期
  OLED_SendCmd(0xf1); //[3:0],PHASE 1;[7:4],PHASE 2;
  OLED_SendCmd(0xDB); //设置VCOMH 电压倍率
  OLED_SendCmd(0x30); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;

  OLED_SendCmd(0xA4); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
  OLED_SendCmd(0xA6); //设置显示方式;bit0:1,反相显示;0,正常显示
  OLED_SendCmd(0xAF); //开启显示 

}


//设定显示位置
void SetDispalyPlace(uint8_t page,uint8_t col)
{
	/*确定显示位置*/
	//列地址-col        
	OLED_SendCmd(0x10 | ((col&0xF0)>>4));
	OLED_SendCmd(0x00 | (col&0x0F)); 	
	//页地址page
	OLED_SendCmd(0xB0+page) ;
}

void OLED_Clear(void)
{
	uint8_t i;
	uint8_t n;
	for(i=0;i<8;i++)
	{
		SetDispalyPlace(i,0);
		/*发送显示数据*/
		for(n=0;n<128;n++)
			OLED_SendData(0);
	}
}

void Display(void)
{
	uint8_t i;
	uint8_t n;
	
	uint8_t flag=0;
	uint8_t data[2]={0x0F,0xF0};
	
	for(i=0;i<8;i++)
	{
		SetDispalyPlace(i,0);
		/*发送显示数据*/
		for(n=0;n<128;n++)
		{
			if(n!=0&&n%4==0)
				flag=!flag;	
			OLED_SendData(data[flag]);
		}
		flag=0;	
	}
}


extern unsigned char Ascii_8X16[];
//显示一个ASCII字符 (页地址，列地址，待显示的ASCII字符)  'A'

void DisplayAscii(uint8_t page,uint8_t col,uint8_t ch) //DisplayAscii(0,0,'A')
{
	uint8_t i;
	uint8_t num;//在数组中是第几个字符
	num=ch-' ';
	
	//上半部分
	SetDispalyPlace(page,col);
	for(i=0;i<8;i++)
	{
		OLED_SendData( Ascii_8X16[ num*16+i ] );
	}
	
	//下班部分
	SetDispalyPlace(page+1,col);
	for(i=0;i<8;i++)
	{
		OLED_SendData( Ascii_8X16[ num*16+8+i ] );
	}
}

//显示一个ASCII字符串  DisplayAsciiString(1,10,"welcome hahaha!!!!")
void DisplayAsciiString(uint8_t page,uint8_t col,char *pch)
{
	while( *pch!='\0' )
	{
		DisplayAscii(page,col,*pch);
		pch++;
		col=col+8;
	}
}

//显示自己的名字

void DisplayPicture(uint8_t page,uint8_t col,uint8_t width,uint8_t hight,uint8_t* p)
{
	uint8_t i,j;
	uint8_t num;
	
	if(hight%8)//有余数
		num=hight/8+1;
	else
		num=hight/8;
	
	for(i=0;i<num;i++)                          
	{                                            
		SetDispalyPlace(page+i,col);
		for(j=0;j<width;j++)
		{
			OLED_SendData( p[i*width+j] );
		}
	}
}
